package com.fingard.dsp.bank.directbank.vbao01;

import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.math.BigDecimal;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directbank.bankInterface.IStatement;
import com.fingard.dsp.bank.reqrespobj.statement.ReqQryStatement;
import com.fingard.dsp.bank.reqrespobj.statement.RetAtsStatement;
import com.fingard.dsp.bank.reqrespobj.statement.TransState;
import com.fingard.dsp.bank.reqrespobj.statement.detail.RetAtsStatementDetail;
import com.fingard.io.FileHelper;
import com.fingard.net.FtpReceiver;
import com.fingard.net.SftpPortClient;
import com.fingard.text.StringHelper;

/**
 * 微保对账单
 * 	   支持：
 * 			1、单笔实时代收付、批量收付
 * 			2、一码付、网关支付
 * 			3、快捷支付
 * 
 * @author cruise
 * @date 2017/6/29
 * @modify 2018/3/29 version 1.0
 */
public class VBAO01Statement extends VBAO01Base implements IStatement {
	public RetAtsStatement d_Qry_Statement(ReqQryStatement p_reqQrySttm) throws Exception {
		RetAtsStatement retAts = new RetAtsStatement(p_reqQrySttm);
		retAts.writeStart();
		
		String[] singleRecPayRespHeader = getSingleRecPayStatement(p_reqQrySttm, retAts);
		String singleRecPayTotalNum = retAts.totalNum;
		
		String[] oneQRPayRespHeader = getOneQRPayStatement(p_reqQrySttm, retAts);
		String oneQRPayTotalNum = retAts.totalNum;
		
		String[] smsRecRespHeader = getSmsRecStatement(p_reqQrySttm, retAts);
		String smsRecTotalNum = retAts.totalNum;
		
		if (singleRecPayRespHeader[0].equals("-1") && oneQRPayRespHeader[0].equals("-1") && smsRecRespHeader[0].equals("-1")) {
			String respInfo = StringHelper.joinNotEmpty("\r\n", "单笔及批量代收付对账单获取失败，原因:" + singleRecPayRespHeader[1], 
					"一码付对账单获取失败，原因:" + oneQRPayRespHeader[1],
					"快捷支付对账单获取失败，原因:" + smsRecRespHeader[1]);
			
			retAts.writeRespCode("-1");
        	retAts.writeRespInfo(respInfo);
		} else {
			if (retAts.getWrittenRdCount() == 0) {
				retAts.writeRespCode("0");
				
				String respInfo = singleRecPayRespHeader[1];
				if (StringHelper.isNullOrEmpty(respInfo)) {
					respInfo = oneQRPayRespHeader[1];
				}
				if (StringHelper.isNullOrEmpty(respInfo)) {
					respInfo = smsRecRespHeader[1];
				}
				if (StringHelper.isNullOrEmpty(respInfo)) {
					respInfo = "交易为空";
				}
				retAts.writeRespInfo(respInfo);
			}
			
			// 获取成功后写入总笔数
			int totalNum = Integer.parseInt(singleRecPayTotalNum) + Integer.parseInt(oneQRPayTotalNum) + Integer.parseInt(smsRecTotalNum);
			retAts.isWritedTotalNum(String.valueOf(totalNum));
		}
		
		retAts.writeEnd();
		return retAts;
	}
	
	/**
	 * (单笔,批量)代收付对账单
	 * 
	 * @param p_reqQrySttm 对账单请求对象
	 * @param retAts 对账单响应对象
	 * @return 对账单响应内容
	 * @throws Exception 通讯异常
	 */
	private String[] getSingleRecPayStatement(ReqQryStatement p_reqQrySttm, RetAtsStatement retAts) throws Exception {
		String[] respHeader = new String[]{"",""};
		
		retAts.totalNum = "0";
		String respCode = "";
		String respInfo = "";
		
		try {
			ActSetItem actItem = getBankConfig().getActSetItem(p_reqQrySttm.actNum, "");
			if (actItem != null) {
				FtpSet ftpSet = bankFront.getFtpSet("");
				if (isEachMerInfo()) {
					String merIdSuffix = getMerIdSuffix(actItem.merchantId);
					ftpSet.userName = actItem.merchantId + merIdSuffix;
					ftpSet.userPassword = actItem.merchantId + merIdSuffix;
					WriteBankLogLn("userName:" + ftpSet.userName);
					WriteBankLogLn("userPwd:" + ftpSet.userPassword);
				}
				
				WriteBankLogLn2("微保单笔实时代收付对账单SFTP服务器地址:" + ftpSet.serverIP + ":" + ftpSet.port);
				
				String downFileName = actItem.merchantId + "_" + p_reqQrySttm.busDate + "_SF.txt";
				WriteBankLogLn2("微保单笔实时代收付对账单所在服务器路径:" + getSFTPDir(ftpSet.downDir) + actItem.merchantId + "/" + downFileName);
				
	            String localFilePath = createTempFileDirectory() + File.separator + downFileName;
	            WriteBankLogLn2("微保单笔实时代收付对账单保存本地路径:" + localFilePath);
				
				SftpPortClient sftp = new SftpPortClient(ftpSet);
	            FtpReceiver ftpReceiver = sftp.downloadFile(actItem.merchantId + "/", downFileName, localFilePath);
	            if (ftpReceiver.isCompleted) {
	            	WriteBankLogLn2("微保单笔实时代收付对账单下载成功!");
	            	
	            	String tmpStrRet = FileHelper.readFileText(localFilePath, getCharset());
	            	WriteBankLogLn2("微保单笔实时代收付对账单响应数据:\r\n" + tmpStrRet);
	            	
	            	/*
	            	 * 单笔实时代收付对账单响应数据格式如下：
	            	 * 商户代号|支付日期(格式yyyyMMdd)|总收款成功笔数|总收款成功金额|总付款成功笔数|总付款成功金额
	            	 *  0       1         2          3                      4          5         6                     7        8        9        10       11   12     13                            14
					 * 序号^交易流水号^商户订单号^商户批次号（批量支付存在）^商户代号^商户产品代号^支付类型（1收款 2付款）^支付金额^商品名称^持卡人姓名^银行名称^卡类型^卡号^交易状态（1收款成功 21付款成功）^交易时间
					 * 序号^交易流水号^商户订单号^商户批次号（批量支付存在）^商户代号^商户产品代号^支付类型（1收款 2付款）^支付金额^商品名称^持卡人姓名^银行名称^卡类型^卡号^交易状态（1收款成功 21付款成功）^交易时间
                     * 
                     * 示例:
                     * 201603180001|20160824|0|0.00|5|1.10
					 * 1^F20160824170524388000032^1^2016080800001^201603180001^HZPF^0.20^2^保险^周盟波^CCB^0^6217000010073664750^21^2016-08-24 17:09:00
					 * 2^F20160824170524388000032^3^2016080800001^201603180001^HZPF^0.30^2^保险^贺晓波^CCB^0^6212260410003258598^21^2016-08-24 17:09:00
					 * 3^20160824173349709000038^00001^F012016082410001^201603180001^HZPF^0.10^2^保险^周盟波^CCB^0^6217000010073664750^21^2016-08-24 17:36:00
					 * 4^20160824173349709000038^00002^F012016082410001^201603180001^HZPF^0.20^2^保险^周盟波^CCB^0^6217000010073664750^21^2016-08-24 17:36:00
					 * 5^20160824173349709000038^00003^F012016082410001^201603180001^HZPF^0.30^2^保险^周盟波^CCB^0^6217000010073664750^21^2016-08-24 17:36:00
	            	 */
	            	
	            	// 解析微保单笔实时收付对账单响应数据
	            	if (StringHelper.hasAnyChar(tmpStrRet)) {
	            		StringReader strReader = new StringReader(tmpStrRet);
						BufferedReader tmpReader = new BufferedReader(strReader);
						
						String totalLine = tmpReader.readLine();
						retAts.totalNum = new BigDecimal(totalLine.split("\\|")[2]).add(new BigDecimal(totalLine.split("\\|")[4])).toString();
						
						while(true) {
							String eachline = tmpReader.readLine();
							if(eachline == null){
								break;
							}
							
							String[] detailNodes = eachline.split("\\^");
							if ("1".equals(detailNodes[13]) || "21".equals(detailNodes[13])) {
								RetAtsStatementDetail tmpRetDetail = new RetAtsStatementDetail();
								
								if (StringHelper.hasAnyChar(detailNodes[2])) {
									tmpRetDetail.askNumber = detailNodes[2];
								}
								
								if (StringHelper.hasAnyChar(detailNodes[3])) {
									tmpRetDetail.reqBatchNO = detailNodes[3];
								}
								
								if (StringHelper.hasAnyChar(detailNodes[6])) {
									String busType = detailNodes[6];
									if ("1".equals(busType)) {
										tmpRetDetail.cdFlag = "22";
									} else {
										tmpRetDetail.cdFlag = "27";
									}
								}
								
								if (StringHelper.hasAnyChar(detailNodes[7])) {
									tmpRetDetail.amount = detailNodes[7];
								}
								
								if (StringHelper.hasAnyChar(detailNodes[14])) {
									tmpRetDetail.busTime = Format.DateTime14Format.format(Format.DateTimeFormat.parse(detailNodes[14]));
								}
								
								if (StringHelper.hasAnyChar(detailNodes[12])) {
									tmpRetDetail.oppAct = detailNodes[12];
								}
								
								if (StringHelper.hasAnyChar(detailNodes[9])) {
									tmpRetDetail.oppActName = detailNodes[9];
								}
								
								tmpRetDetail.transState = TransState.Success;
			    				
				        		retAts.writeRetDetail(tmpRetDetail);
							}
						}
	            	} else {
	            		respCode = "-1";
		    			respInfo = "微保单笔实时代收付对账单内容为空,请联系微保相关技术人员!";
	            	}
	            } else {
	            	respCode = "-1";
	    			respInfo = "微保单笔实时代收付对账单下载失败,原因:\r\n" + ftpReceiver.connMsg;
	            }
			} else {
				respCode = "-1";
				respInfo = "未找到账号[" + p_reqQrySttm.actNum + "]商户配置信息";
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			respCode = "-1";
			respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		}
		
		respHeader[0] = respCode;
		respHeader[1] = respInfo;
		
		return respHeader;
	}
	
	/**
	 * 网关、移动支付对账单
	 * 
	 * @param p_reqQrySttm 对账单请求对象
	 * @param retAts 对账单响应对象
	 * @return 响应内容
	 * @throws Exception 通讯异常
	 */
	private String[] getOneQRPayStatement(ReqQryStatement p_reqQrySttm, RetAtsStatement retAts) throws Exception {
		String[] respHeader = new String[]{"",""};
		
		retAts.totalNum = "0";
		String respCode = "";
		String respInfo = "";
		
		try {
			ActSetItem actItem = getBankConfig().getActSetItem(p_reqQrySttm.actNum, "unifiedorder");
			if (actItem != null) {
				FtpSet ftpSet = bankFront.getFtpSet("");
				if (isEachMerInfo()) {
					String merIdSuffix = getMerIdSuffix(actItem.merchantId);
					ftpSet.userName = actItem.merchantId + merIdSuffix;
					ftpSet.userPassword = actItem.merchantId + merIdSuffix;
					WriteBankLogLn("userName:" + ftpSet.userName);
					WriteBankLogLn("userPwd:" + ftpSet.userPassword);
				}
				WriteBankLogLn2("微保一码付对账单SFTP服务器地址:" + ftpSet.serverIP + ":" + ftpSet.port);
				
				String downFileName = actItem.merchantId + "_" + p_reqQrySttm.busDate + "_WY.txt";
				WriteBankLogLn2("微保一码付对账单所在服务器路径:" + getSFTPDir(ftpSet.downDir) + actItem.merchantId + "/" + downFileName);
				
	            String localFilePath = createTempFileDirectory() + File.separator + downFileName;
	            WriteBankLogLn2("微保一码付对账单保存本地路径:" + localFilePath);
				
				SftpPortClient sftp = new SftpPortClient(ftpSet);
	            FtpReceiver ftpReceiver = sftp.downloadFile(actItem.merchantId + "/", downFileName, localFilePath);
	            if (ftpReceiver.isCompleted) {
	            	WriteBankLogLn2("微保一码付对账单下载成功!");
	            	
	            	String tmpStrRet = FileHelper.readFileText(localFilePath, getCharset());
	            	WriteBankLogLn2("微保一码付对账单响应数据:\r\n" + tmpStrRet);
	            	
	            	/*
	            	 * 一码付对账单响应数据格式如下：
	            	 * 商户代号|支付日期(格式yyyyMMdd)|总收款成功笔数|总收款成功金额|总退款成功笔数|总退款成功金额
                     * 序号^交易流水号^商户订单号^退款流水号^商户退款订单号^商户代号^支付产品代号^金额^交易状态（1支付成功 11退款成功）^交易时间
                     * 序号^交易流水号^商户订单号^退款流水号^商户退款订单号^商户代号^支付产品代号^金额^交易状态（1支付成功 11退款成功）^交易时间
                     * 
                     * 示例:
                     * 201603180001|20170109|3|90.00|0|0.00
					 * 1^20170109115113224005370^ZXWFT8870515994446^^^201603180001^ZXWFT^40.00^1^2017-01-09 11:52:20
					 * 2^20170109114756943005343^ZXWFT8674431921074^^^201603180001^ZXWFT^30.00^1^2017-01-09 11:49:05
					 * 3^20170109114124963005275^ZXWFT8282215289740^^^201603180001^ZXWFT^20.00^1^2017-01-09 11:47:46
	            	 */
	            	
	            	// 解析微保一码付对账单响应数据
	            	
	            	if (StringHelper.hasAnyChar(tmpStrRet)) {
	            		StringReader strReader = new StringReader(tmpStrRet);
						BufferedReader tmpReader = new BufferedReader(strReader);
						
						String totalLine = tmpReader.readLine();
						retAts.totalNum = totalLine.split("\\|")[2];
						
						while(true) {
							String eachline = tmpReader.readLine();
							if(eachline == null){
								break;
							}
							
							String[] detailNodes = eachline.split("\\^");
							if ("1".equals(detailNodes[8])) {
								RetAtsStatementDetail p_retDetail = new RetAtsStatementDetail();
								
								if (StringHelper.hasAnyChar(detailNodes[2])) {
									p_retDetail.askNumber = detailNodes[2];
								}
								
								if (StringHelper.hasAnyChar(detailNodes[7])) {
									p_retDetail.amount = detailNodes[7];
								}
								
								p_retDetail.cdFlag = "22";
								
								if (StringHelper.hasAnyChar(detailNodes[9])) {
									p_retDetail.busTime = Format.DateTime14Format.format(Format.DateTimeFormat.parse(detailNodes[9]));
								}
								
			    				p_retDetail.transState = TransState.Success;
			    				
				        		retAts.writeRetDetail(p_retDetail);
							}
						}
	            	} else {
	            		respCode = "-1";
		    			respInfo = "微保一码付对账单内容为空,请联系微保相关技术人员!";
	            	}
	            } else {
	            	respCode = "-1";
	    			respInfo = "微保一码付对账单文件下载失败,原因:\r\n" + ftpReceiver.connMsg;
	    			WriteBankLogLn2("微保一码付对账单文件下载失败,原因:\r\n" + ftpReceiver.connMsg);
	            }
			} else {
				respCode = "-1";
				respInfo = "未找到账号[" + p_reqQrySttm.actNum + "]商户配置信息";
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			respCode = "-1";
			respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		}
		
		respHeader[0] = respCode;
		respHeader[1] = respInfo;
		
		return respHeader;
	}
	
	/**
	 * 快捷支付对战单
	 * 
	 * @param p_reqQrySttm
	 * @param retAts
	 * @return
	 * @throws Exception
	 */
	private String[] getSmsRecStatement(ReqQryStatement p_reqQrySttm, RetAtsStatement retAts) throws Exception {
		String[] respHeader = new String[]{"",""};
		
		retAts.totalNum = "0";
		String respCode = "";
		String respInfo = "";
		
		try {
			ActSetItem actItem = getBankConfig().getActSetItem(p_reqQrySttm.actNum, "smsRec");
			if (actItem != null) {
				FtpSet ftpSet = bankFront.getFtpSet("");
				if (isEachMerInfo()) {
					String merIdSuffix = getMerIdSuffix(actItem.merchantId);
					ftpSet.userName = actItem.merchantId + merIdSuffix;
					ftpSet.userPassword = actItem.merchantId + merIdSuffix;
					WriteBankLogLn("userName:" + ftpSet.userName);
					WriteBankLogLn("userPwd:" + ftpSet.userPassword);
				}
				WriteBankLogLn("微保快捷支付对账单SFTP服务器地址:- [" + ftpSet.serverIP + ":" + ftpSet.port + "].");
				
				String downFileName = actItem.merchantId + "_" + p_reqQrySttm.busDate + "_COMBINEDTRADE.txt";
				WriteBankLogLn("微保快捷支付对账单SFTP服务器路径:" + getSFTPDir(ftpSet.downDir) + actItem.merchantId + "/" + downFileName);
				
	            String localFilePath = createTempFileDirectory() + File.separator + downFileName;
	            WriteBankLogLn("微保快捷支付对账单保存本地路径:" + localFilePath);
				
				SftpPortClient sftp = new SftpPortClient(ftpSet);
	            FtpReceiver ftpReceiver = sftp.downloadFile(actItem.merchantId + "/", downFileName, localFilePath);
	            if (ftpReceiver.isCompleted) {
	            	WriteBankLogLn("微保快捷支付对账单下载成功,开始解析...");
	            	String tmpStrRet = FileHelper.readFileText(localFilePath, getCharset());
	            	WriteBankLogLn2("微保快捷支付对账单文件内容:\r\n" + tmpStrRet);
	            	
	            	if (StringHelper.hasAnyChar(tmpStrRet)) {
	            		StringReader strReader = new StringReader(tmpStrRet);
						BufferedReader tmpReader = new BufferedReader(strReader);
						tmpReader.readLine();
						
						retAts.totalNum = "0";
						int totalNum = 0;
						while(true) {
							String eachline = tmpReader.readLine();
							if(eachline == null){
								break;
							}
							
							String[] detailNodes = eachline.split("\\^");
							if ("1".equals(detailNodes[9])) {
								totalNum++;
								RetAtsStatementDetail tmpRetDetail = new RetAtsStatementDetail();
								
								// 微保快捷对账单会返回鉴权和快捷支付两种数据，鉴权数据需要过滤
								String askNumber = detailNodes[3];
								if (StringHelper.hasAnyChar(askNumber)) {
									tmpRetDetail.askNumber = detailNodes[3];
									if (StringHelper.hasAnyChar(detailNodes[11])) {
										tmpRetDetail.busTime = Format.DateTime14Format.format(Format.DateTimeFormat.parse(detailNodes[11]));
									}
									tmpRetDetail.amount = detailNodes[5];
									tmpRetDetail.oppAct = detailNodes[6];
									tmpRetDetail.oppActName = detailNodes[7];
									tmpRetDetail.bkSeq = detailNodes[1];
									tmpRetDetail.cdFlag = "22";
									tmpRetDetail.transState = TransState.Success;
									
					        		retAts.writeRetDetail(tmpRetDetail);
								}
							}
						}
						retAts.totalNum = String.valueOf(totalNum);
	            	} else {
	            		respCode = "-1";
		    			respInfo = "微保快捷支付对账单内容为空,请联系微保相关技术人员!";
	            	}
	            } else {
	            	respCode = "-1";
	    			respInfo = "微保快捷支付对账单文件下载失败,原因:\r\n" + ftpReceiver.connMsg;
	            }
			} else {
				respCode = "-1";
				respInfo = "未找到账号:[" + p_reqQrySttm.actNum + "]商户配置信息";
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			respCode = "-1";
			respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		}
		
		respHeader[0] = respCode;
		respHeader[1] = respInfo;
		
		return respHeader;
	}
}
